/*	$OpenBSD: fp.S,v 1.6 2004/10/30 14:48:59 pefo Exp $	*/
/*
 * Copyright (c) 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Ralph Campbell.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	from: @(#)fp.s	8.1 (Berkeley) 6/10/93
 *      $Id: fp.S,v 1.7 2004/11/02 18:54:45 pefo Exp $
 */

/*
 * Standard header stuff.
 */

#include <machine/regdef.h>
#include <machine/asm.h>
#include <machine/regnum.h>
#include <machine/cpu.h>

#include "assym.h"

#define SEXP_INF	0xff
#define DEXP_INF	0x7ff
#define SEXP_BIAS	127
#define DEXP_BIAS	1023
#define SEXP_MIN	-126
#define DEXP_MIN	-1022
#define SEXP_MAX	127
#define DEXP_MAX	1023
#define WEXP_MAX	30		/* maximum unbiased exponent for int */
#define WEXP_MIN	-1		/* minimum unbiased exponent for int */
#define SFRAC_BITS	23
#define DFRAC_BITS	52
#define SIMPL_ONE	0x00800000
#define DIMPL_ONE	0x0010000000000000
#define SLEAD_ZEROS	63 - 55
#define DLEAD_ZEROS	63 - 52
#define STICKYBIT	1
#define GUARDBIT	0x0000000080000000
#define DGUARDBIT	0x8000000000000000

#define SSIGNAL_NAN	0x00400000
#define DSIGNAL_NAN	0x00080000
#define SQUIET_NAN	0x003fffff
#define DQUIET_NAN	0x0007ffffffffffff
#define INT_MIN		0x80000000
#define INT_MAX		0x7fffffff

#define COND_UNORDERED	0x1
#define COND_EQUAL	0x2
#define COND_LESS	0x4
#define COND_SIGNAL	0x8

/*----------------------------------------------------------------------------
 *
 * MipsEmulateFP --
 *
 *	Emulate unimplemented floating point operations.
 *	This routine should only be called by MipsFPInterrupt()
 *	and only if this is a COP1 instruction.
 *
 *	MipsEmulateFP(instr)
 *		unsigned instr;
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Floating point registers are modified according to instruction.
 *
 *----------------------------------------------------------------------------
 */
NON_LEAF(MipsEmulateFP, FRAMESZ(CF_SZ), ra)
	PTR_SUB	sp, sp, FRAMESZ(CF_SZ)
	PTR_S	ra, CF_RA_OFFS(sp)

	srl	v0, a0, 21			# get FMT field
	and	v0, v0, 0x1f			# mask FMT field
	dla	a3, func_s
	beq	v0, 0x10, 1f
	dla	a3, func_d
	beq	v0, 0x11, 1f
	dla	a3, func_w
	beq	v0, 0x14, 1f
	dla	a3, func_l
	beq	v0, 0x15, 1f
	b	ill				# illegal format

1:
	and	v1, a0, 0x3f			# mask FUNC field
	sll	v1, v1, 3			# align for table lookup
	daddu	v1, a3
	cfc1	a1, FPC_CSR			# get exception register
	ld	a3, (v1)			# switch on FUNC & FMT
	and	a1, a1, ~FPC_EXCEPTION_UNIMPL	# clear exception
	ctc1	a1, FPC_CSR
	j	a3

	.rdata
func_s:
	.dword	add_s		# 0
	.dword	sub_s		# 1
	.dword	mul_s		# 2
	.dword	div_s		# 3
	.dword	ill		# 4
	.dword	abs_s		# 5
	.dword	mov_s		# 6
	.dword	neg_s		# 7
	.dword	ill		# 8
	.dword	ill		# 9
	.dword	ill		# 10
	.dword	ill		# 11
	.dword	round_w_s	# 12
	.dword	trunc_w_s	# 13
	.dword	ceil_w_s	# 14
	.dword	floor_w_s	# 15
	.dword	ill		# 16
	.dword	ill		# 17
	.dword	ill		# 18
	.dword	ill		# 19
	.dword	ill		# 20
	.dword	ill		# 21
	.dword	ill		# 22
	.dword	ill		# 23
	.dword	ill		# 24
	.dword	ill		# 25
	.dword	ill		# 26
	.dword	ill		# 27
	.dword	ill		# 28
	.dword	ill		# 29
	.dword	ill		# 30
	.dword	ill		# 31
	.dword	ill		# 32
	.dword	cvt_d_s		# 33
	.dword	ill		# 34
	.dword	ill		# 35
	.dword	cvt_w_s		# 36
	.dword	ill		# 37
	.dword	ill		# 38
	.dword	ill		# 39
	.dword	ill		# 40
	.dword	ill		# 41
	.dword	ill		# 42
	.dword	ill		# 43
	.dword	ill		# 44
	.dword	ill		# 45
	.dword	ill		# 46
	.dword	ill		# 47
	.dword	cmp_s		# 48
	.dword	cmp_s		# 49
	.dword	cmp_s		# 50
	.dword	cmp_s		# 51
	.dword	cmp_s		# 52
	.dword	cmp_s		# 53
	.dword	cmp_s		# 54
	.dword	cmp_s		# 55
	.dword	cmp_s		# 56
	.dword	cmp_s		# 57
	.dword	cmp_s		# 58
	.dword	cmp_s		# 59
	.dword	cmp_s		# 60
	.dword	cmp_s		# 61
	.dword	cmp_s		# 62
	.dword	cmp_s		# 63

func_d:
	.dword	add_d		# 0
	.dword	sub_d		# 1
	.dword	mul_d		# 2
	.dword	div_d		# 3
	.dword	ill		# 4
	.dword	abs_d		# 5
	.dword	mov_d		# 6
	.dword	neg_d		# 7
	.dword	ill		# 8
	.dword	ill		# 9
	.dword	ill		# 10
	.dword	ill		# 11
	.dword	round_w_d	# 12
	.dword	trunc_w_d	# 13
	.dword	ceil_w_d	# 14
	.dword	floor_w_d	# 15
	.dword	ill		# 16
	.dword	ill		# 17
	.dword	ill		# 18
	.dword	ill		# 19
	.dword	ill		# 20
	.dword	ill		# 21
	.dword	ill		# 22
	.dword	ill		# 23
	.dword	ill		# 24
	.dword	ill		# 25
	.dword	ill		# 26
	.dword	ill		# 27
	.dword	ill		# 28
	.dword	ill		# 29
	.dword	ill		# 30
	.dword	ill		# 31
	.dword	cvt_s_d		# 32
	.dword	ill		# 33
	.dword	ill		# 34
	.dword	ill		# 35
	.dword	cvt_w_d		# 36
	.dword	ill		# 37
	.dword	ill		# 38
	.dword	ill		# 39
	.dword	ill		# 40
	.dword	ill		# 41
	.dword	ill		# 42
	.dword	ill		# 43
	.dword	ill		# 44
	.dword	ill		# 45
	.dword	ill		# 46
	.dword	ill		# 47
	.dword	cmp_d		# 48
	.dword	cmp_d		# 49
	.dword	cmp_d		# 50
	.dword	cmp_d		# 51
	.dword	cmp_d		# 52
	.dword	cmp_d		# 53
	.dword	cmp_d		# 54
	.dword	cmp_d		# 55
	.dword	cmp_d		# 56
	.dword	cmp_d		# 57
	.dword	cmp_d		# 58
	.dword	cmp_d		# 59
	.dword	cmp_d		# 60
	.dword	cmp_d		# 61
	.dword	cmp_d		# 62
	.dword	cmp_d		# 63

func_w:
	.dword	ill		# 0
	.dword	ill		# 1
	.dword	ill		# 2
	.dword	ill		# 3
	.dword	ill		# 4
	.dword	ill		# 5
	.dword	ill		# 6
	.dword	ill		# 7
	.dword	ill		# 8
	.dword	ill		# 9
	.dword	ill		# 10
	.dword	ill		# 11
	.dword	ill		# 12
	.dword	ill		# 13
	.dword	ill		# 14
	.dword	ill		# 15
	.dword	ill		# 16
	.dword	ill		# 17
	.dword	ill		# 18
	.dword	ill		# 19
	.dword	ill		# 20
	.dword	ill		# 21
	.dword	ill		# 22
	.dword	ill		# 23
	.dword	ill		# 24
	.dword	ill		# 25
	.dword	ill		# 26
	.dword	ill		# 27
	.dword	ill		# 28
	.dword	ill		# 29
	.dword	ill		# 30
	.dword	ill		# 31
	.dword	cvt_s_w		# 32
	.dword	cvt_d_w		# 33
	.dword	ill		# 34
	.dword	ill		# 35
	.dword	ill		# 36
	.dword	ill		# 37
	.dword	ill		# 38
	.dword	ill		# 39
	.dword	ill		# 40
	.dword	ill		# 41
	.dword	ill		# 42
	.dword	ill		# 43
	.dword	ill		# 44
	.dword	ill		# 45
	.dword	ill		# 46
	.dword	ill		# 47
	.dword	ill		# 48
	.dword	ill		# 49
	.dword	ill		# 50
	.dword	ill		# 51
	.dword	ill		# 52
	.dword	ill		# 53
	.dword	ill		# 54
	.dword	ill		# 55
	.dword	ill		# 56
	.dword	ill		# 57
	.dword	ill		# 58
	.dword	ill		# 59
	.dword	ill		# 60
	.dword	ill		# 61
	.dword	ill		# 62
	.dword	ill		# 63

func_l:
	.dword	ill		# 0
	.dword	ill		# 1
	.dword	ill		# 2
	.dword	ill		# 3
	.dword	ill		# 4
	.dword	ill		# 5
	.dword	ill		# 6
	.dword	ill		# 7
	.dword	ill		# 8
	.dword	ill		# 9
	.dword	ill		# 10
	.dword	ill		# 11
	.dword	ill		# 12
	.dword	ill		# 13
	.dword	ill		# 14
	.dword	ill		# 15
	.dword	ill		# 16
	.dword	ill		# 17
	.dword	ill		# 18
	.dword	ill		# 19
	.dword	ill		# 20
	.dword	ill		# 21
	.dword	ill		# 22
	.dword	ill		# 23
	.dword	ill		# 24
	.dword	ill		# 25
	.dword	ill		# 26
	.dword	ill		# 27
	.dword	ill		# 28
	.dword	ill		# 29
	.dword	ill		# 30
	.dword	ill		# 31
	.dword	cvt_s_l		# 32
	.dword	cvt_d_l		# 33
	.dword	ill		# 34
	.dword	ill		# 35
	.dword	ill		# 36
	.dword	ill		# 37
	.dword	ill		# 38
	.dword	ill		# 39
	.dword	ill		# 40
	.dword	ill		# 41
	.dword	ill		# 42
	.dword	ill		# 43
	.dword	ill		# 44
	.dword	ill		# 45
	.dword	ill		# 46
	.dword	ill		# 47
	.dword	ill		# 48
	.dword	ill		# 49
	.dword	ill		# 50
	.dword	ill		# 51
	.dword	ill		# 52
	.dword	ill		# 53
	.dword	ill		# 54
	.dword	ill		# 55
	.dword	ill		# 56
	.dword	ill		# 57
	.dword	ill		# 58
	.dword	ill		# 59
	.dword	ill		# 60
	.dword	ill		# 61
	.dword	ill		# 62
	.dword	ill		# 63

	.text

/*
 * Single precision subtract.
 */
sub_s:
	jal	get_ft_fs_s
	xor	ta0, 1				# negate FT sign bit
	b	add_sub_s
/*
 * Single precision add.
 */
add_s:
	jal	get_ft_fs_s
add_sub_s:
	bne	t1, SEXP_INF, 1f		# is FS an infinity?
	bne	ta1, SEXP_INF, result_fs_s	# if FT is not inf, result=FS
	bne	t2, zero, result_fs_s		# if FS is NAN, result is FS
	bne	ta2, zero, result_ft_s		# if FT is NAN, result is FT
	bne	t0, ta0, invalid_s		# both infinities same sign?
	b	result_fs_s			# result is in FS
1:
	beq	ta1, SEXP_INF, result_ft_s	# if FT is inf, result=FT
	bne	t1, zero, 4f			# is FS a denormalized num?
	beq	t2, zero, 3f			# is FS zero?
	bne	ta1, zero, 2f			# is FT a denormalized num?
	beq	ta2, zero, result_fs_s		# FT is zero, result=FS
	jal	renorm_fs_s
	jal	renorm_ft_s
	b	5f
2:
	jal	renorm_fs_s
	subu	ta1, ta1, SEXP_BIAS		# unbias FT exponent
	or	ta2, ta2, SIMPL_ONE		# set implied one bit
	b	5f
3:
	bne	ta1, zero, result_ft_s		# if FT != 0, result=FT
	bne	ta2, zero, result_ft_s
	and	v0, a1, FPC_ROUNDING_BITS	# get rounding mode
	bne	v0, FPC_ROUND_RM, 1f	# round to -infinity?
	or	t0, t0, ta0			# compute result sign
	b	result_fs_s
1:
	and	t0, ta0				# compute result sign
	b	result_fs_s
4:
	bne	ta1, zero, 2f			# is FT a denormalized num?
	beq	ta2, zero, result_fs_s		# FT is zero, result=FS
	subu	t1, SEXP_BIAS			# unbias FS exponent
	or	t2, SIMPL_ONE			# set implied one bit
	jal	renorm_ft_s
	b	5f
2:
	subu	t1, SEXP_BIAS			# unbias FS exponent
	or	t2, SIMPL_ONE			# set implied one bit
	subu	ta1, SEXP_BIAS			# unbias FT exponent
	or	ta2, SIMPL_ONE			# set implied one bit
/*
 * Perform the addition.
 */
5:
	move	t8, zero			# no shifted bits (sticky reg)
	beq	t1, ta1, 4f			# exp equal, no shift needed
	subu	v0, t1, ta1			# v0 = difference of exponents
	move	v1, v0				# v1 = abs(difference)
	bge	v0, zero, 1f
	negu	v1
1:
	ble	v1, SFRAC_BITS+2, 2f		# is difference too great?
	li	t8, STICKYBIT			# set the sticky bit
	bge	v0, zero, 1f			# check which exp is larger
	move	t1, ta1				# result exp is FTs
	move	t2, zero			# FSs fraction shifted is zero
	b	4f
1:
	move	ta2, zero			# FTs fraction shifted is zero
	b	4f
2:
	li	t9, 32				# compute 32 - abs(exp diff)
	subu	t9, t9, v1
	bgt	v0, zero, 3f			# if FS > FT, shift FTs frac
	move	t1, ta1				# FT > FS, result exp is FTs
	sll	t8, t2, t9			# save bits shifted out
	srl	t2, t2, v1			# shift FSs fraction
	b	4f
3:
	sll	t8, ta2, t9			# save bits shifted out
	srl	ta2, ta2, v1			# shift FTs fraction
4:
	bne	t0, ta0, 1f			# if signs differ, subtract
	addu	t2, t2, ta2			# add fractions
	b	norm_s
1:
	blt	t2, ta2, 3f			# subtract larger from smaller
	bne	t2, ta2, 2f			# if same, result=0
	move	t1, zero			# result=0
	move	t2, zero
	and	v0, a1, FPC_ROUNDING_BITS	# get rounding mode
	bne	v0, FPC_ROUND_RM, 1f	# round to -infinity?
	or	t0, t0, ta0			# compute result sign
	b	result_fs_s
1:
	and	t0, t0, ta0			# compute result sign
	b	result_fs_s
2:
	sltu	t9, zero, t8			# compute t2:zero - ta2:t8
	subu	t8, zero, t8
	subu	t2, t2, ta2			# subtract fractions
	subu	t2, t2, t9			# subtract barrow
	b	norm_s
3:
	move	t0, ta0				# sign of result = FTs
	sltu	t9, zero, t8			# compute ta2:zero - t2:t8
	subu	t8, zero, t8
	subu	t2, ta2, t2			# subtract fractions
	subu	t2, t2, t9			# subtract barrow
	b	norm_s

/*
 * Double precision subtract.
 */
sub_d:
	jal	get_ft_fs_d
	xor	ta0, ta0, 1			# negate sign bit
	b	add_sub_d
/*
 * Double precision add.
 */
add_d:
	jal	get_ft_fs_d
add_sub_d:
	bne	t1, DEXP_INF, 1f		# is FS an infinity?
	bne	ta1, DEXP_INF, result_fs_d	# if FT is not inf, result=FS
	bne	t2, zero, result_fs_d		# if FS is NAN, result is FS
	bne	ta2, zero, result_ft_d		# if FT is NAN, result is FT
	bne	t0, ta0, invalid_d		# both infinities same sign?
	b	result_fs_d			# result is in FS
1:
	beq	ta1, DEXP_INF, result_ft_d	# if FT is inf, result=FT
	bne	t1, zero, 4f			# is FS a denormalized num?
	beq	t2, zero, 3f			# is FS zero?
	bne	ta1, zero, 2f			# is FT a denormalized num?
	beq	ta2, zero, result_fs_d		# FT is zero, result=FS
	jal	renorm_fs_d
	jal	renorm_ft_d
	b	5f
2:
	jal	renorm_fs_d
	subu	ta1, ta1, DEXP_BIAS		# unbias FT exponent
	or	ta2, ta2, DIMPL_ONE		# set implied one bit
	b	5f
3:
	bne	ta1, zero, result_ft_d		# if FT != 0, result=FT
	bne	ta2, zero, result_ft_d
	and	v0, a1, FPC_ROUNDING_BITS	# get rounding mode
	bne	v0, FPC_ROUND_RM, 1f	# round to -infinity?
	or	t0, t0, ta0			# compute result sign
	b	result_fs_d
1:
	and	t0, t0, ta0			# compute result sign
	b	result_fs_d
4:
	bne	ta1, zero, 2f			# is FT a denormalized num?
	beq	ta2, zero, result_fs_d		# FT is zero, result=FS
	subu	t1, t1, DEXP_BIAS		# unbias FS exponent
	or	t2, t2, DIMPL_ONE		# set implied one bit
	jal	renorm_ft_d
	b	5f
2:
	subu	t1, t1, DEXP_BIAS		# unbias FS exponent
	or	t2, t2, DIMPL_ONE		# set implied one bit
	subu	ta1, ta1, DEXP_BIAS		# unbias FT exponent
	or	ta2, ta2, DIMPL_ONE		# set implied one bit
/*
 * Perform the addition.
 */
5:
	move	t8, zero			# no shifted bits (sticky reg)
	beq	t1, ta1, 4f			# no shift needed
	subu	v0, t1, ta1			# v0 = difference of exponents
	move	v1, v0				# v1 = abs(difference)
	bge	v0, zero, 1f
	negu	v1
1:
	ble	v1, DFRAC_BITS+2, 2f		# is difference too great?
	li	t8, STICKYBIT			# set the sticky bit
	bge	v0, zero, 1f			# check which exp is larger
	move	t1, ta1				# result exp is FTs
	move	t2, zero			# FSs fraction shifted is zero
	b	4f
1:
	move	ta2, zero			# FTs fraction shifted is zero
	b	4f
2:
	li	t9, 64
	subu	t9, t9, v1
	bge	v0, zero, 3f			# if FS > FT, shift FTs frac
	move	t1, ta1				# FT > FS, result exp is FTs
	dsll	t8, t2, t9			# save bits shifted out
	dsrl	t2, t2, v1
	b	4f
3:
	dsll	t8, ta2, t9			# save bits shifted out
	dsrl	ta2, ta2, v1
4:
	bne	t0, ta0, 1f			# if signs differ, subtract
	daddu	t2, ta2				# add fractions
	b	norm_d
1:
	blt	t2, ta2, 3f			# subtract larger from smaller
	bne	t2, ta2, 2f
	move	t1, zero			# result=0
	move	t2, zero
	and	v0, a1, FPC_ROUNDING_BITS	# get rounding mode
	bne	v0, FPC_ROUND_RM, 1f	# round to -infinity?
	or	t0, t0, ta0			# compute result sign
	b	result_fs_d
1:
	and	t0, t0, ta0			# compute result sign
	b	result_fs_d
2:
	sltu	t9, zero, t8			# compute t2:zero - ta2:t8
	dsubu	t8, zero, t8
	dsubu	t2, t2, ta2			# subtract fractions
	dsubu	t2, t2, t9			# subtract barrow
	b	norm_d
3:
	move	t0, ta0				# sign of result = FTs
	sltu	t9, zero, t8
	dsubu	t2, ta2, t2			# subtract fractions
	dsubu	t2, t2, t9			# subtract barrow
	b	norm_d

/*
 * Single precision multiply.
 */
mul_s:
	jal	get_ft_fs_s
	xor	t0, t0, ta0			# compute sign of result
	move	ta0, t0
	bne	t1, SEXP_INF, 2f		# is FS an infinity?
	bne	t2, zero, result_fs_s		# if FS is a NAN, result=FS
	bne	ta1, SEXP_INF, 1f		# FS is inf, is FT an infinity?
	bne	ta2, zero, result_ft_s		# if FT is a NAN, result=FT
	b	result_fs_s			# result is infinity
1:
	bne	ta1, zero, result_fs_s		# inf * zero? if no, result=FS
	bne	ta2, zero, result_fs_s
	b	invalid_s			# infinity * zero is invalid
2:
	bne	ta1, SEXP_INF, 1f		# FS != inf, is FT an infinity?
	bne	t1, zero, result_ft_s		# zero * inf? if no, result=FT
	bne	t2, zero, result_ft_s
	bne	ta2, zero, result_ft_s		# if FT is a NAN, result=FT
	b	invalid_s			# zero * infinity is invalid
1:
	bne	t1, zero, 1f			# is FS zero?
	beq	t2, zero, result_fs_s		# result is zero
	jal	renorm_fs_s
	b	2f
1:
	subu	t1, t1, SEXP_BIAS		# unbias FS exponent
	or	t2, t2, SIMPL_ONE		# set implied one bit
2:
	bne	ta1, zero, 1f			# is FT zero?
	beq	ta2, zero, result_ft_s		# result is zero
	jal	renorm_ft_s
	b	2f
1:
	subu	ta1, ta1, SEXP_BIAS		# unbias FT exponent
	or	ta2, ta2, SIMPL_ONE		# set implied one bit
2:
	addu	t1, t1, ta1			# compute result exponent
	addu	t1, t1, 9			# account for binary point
	multu	t2, ta2				# multiply fractions
	mflo	t8
	mfhi	t2
	b	norm_s

/*
 * Double precision multiply.
 */
mul_d:
	jal	get_ft_fs_d
	xor	t0, t0, ta0			# compute sign of result
	move	ta0, t0
	bne	t1, DEXP_INF, 2f		# is FS an infinity?
	bne	t2, zero, result_fs_d		# if FS is a NAN, result=FS
	bne	ta1, DEXP_INF, 1f		# FS is inf, is FT an infinity?
	bne	ta2, zero, result_ft_d		# if FT is a NAN, result=FT
	b	result_fs_d			# result is infinity
1:
	bne	ta1, zero, result_fs_d		# inf * zero? if no, result=FS
	bne	ta2, zero, result_fs_d
	b	invalid_d			# infinity * zero is invalid
2:
	bne	ta1, DEXP_INF, 1f		# FS != inf, is FT an infinity?
	bne	t1, zero, result_ft_d		# zero * inf? if no, result=FT
	bne	t2, zero, result_ft_d		# if FS is a NAN, result=FS
	bne	ta2, zero, result_ft_d		# if FT is a NAN, result=FT
	b	invalid_d			# zero * infinity is invalid
1:
	bne	t1, zero, 2f			# is FS zero?
	beq	t2, zero, result_fs_d		# result is zero
	jal	renorm_fs_d
	b	3f
2:
	subu	t1, t1, DEXP_BIAS		# unbias FS exponent
	or	t2, t2, DIMPL_ONE		# set implied one bit
3:
	bne	ta1, zero, 2f			# is FT zero?
	beq	ta2, zero, result_ft_d		# result is zero
	jal	renorm_ft_d
	b	3f
2:
	subu	ta1, ta1, DEXP_BIAS		# unbias FT exponent
	or	ta2, ta2, DIMPL_ONE		# set implied one bit
3:
	addu	t1, t1, ta1			# compute result exponent
	addu	t1, t1, 12			# ???
	dmultu	t2, ta2				# multiply fractions
	mflo	t8
	mfhi	t2
	b	norm_d

/*
 * Single precision divide.
 */
div_s:
	jal	get_ft_fs_s
	xor	t0, t0, ta0			# compute sign of result
	move	ta0, t0
	bne	t1, SEXP_INF, 1f		# is FS an infinity?
	bne	t2, zero, result_fs_s		# if FS is NAN, result is FS
	bne	ta1, SEXP_INF, result_fs_s	# is FT an infinity?
	bne	ta2, zero, result_ft_s		# if FT is NAN, result is FT
	b	invalid_s			# infinity/infinity is invalid
1:
	bne	ta1, SEXP_INF, 1f		# is FT an infinity?
	bne	ta2, zero, result_ft_s		# if FT is NAN, result is FT
	move	t1, zero			# x / infinity is zero
	move	t2, zero
	b	result_fs_s
1:
	bne	t1, zero, 2f			# is FS zero?
	bne	t2, zero, 1f
	bne	ta1, zero, result_fs_s		# FS=zero, is FT zero?
	beq	ta2, zero, invalid_s		# 0 / 0
	b	result_fs_s			# result = zero
1:
	jal	renorm_fs_s
	b	3f
2:
	subu	t1, t1, SEXP_BIAS		# unbias FS exponent
	or	t2, t2, SIMPL_ONE		# set implied one bit
3:
	bne	ta1, zero, 2f			# is FT zero?
	bne	ta2, zero, 1f
	or	a1, a1, FPC_EXCEPTION_DIV0 | FPC_STICKY_DIV0
	and	v0, a1, FPC_ENABLE_DIV0	# trap enabled?
	bne	v0, zero, fpe_trap
	ctc1	a1, FPC_CSR		# save exceptions
	li	t1, SEXP_INF			# result is infinity
	move	t2, zero
	b	result_fs_s
1:
	jal	renorm_ft_s
	b	3f
2:
	subu	ta1, ta1, SEXP_BIAS		# unbias FT exponent
	or	ta2, ta2, SIMPL_ONE		# set implied one bit
3:
	subu	t1, t1, ta1			# compute exponent
	subu	t1, t1, 3			# compensate for result position
	li	v0, SFRAC_BITS+3		# number of bits to divide
	move	t8, t2				# init dividend
	move	t2, zero			# init result
1:
	bltu	t8, ta2, 3f			# is dividend >= divisor?
2:
	subu	t8, t8, ta2			# subtract divisor from dividend
	or	t2, t2, 1			# remember that we did
	bne	t8, zero, 3f			# if not done, continue
	sll	t2, t2, v0			# shift result to final position
	b	norm_s
3:
	sll	t8, t8, 1			# shift dividend
	sll	t2, t2, 1			# shift result
	subu	v0, v0, 1			# are we done?
	bne	v0, zero, 1b			# no, continue
	b	norm_s

/*
 * Double precision divide.
 */
div_d:
	jal	get_ft_fs_d
	xor	t0, t0, ta0			# compute sign of result
	move	ta0, t0
	bne	t1, DEXP_INF, 1f		# is FS an infinity?
	bne	t2, zero, result_fs_d		# if FS is NAN, result is FS
	bne	ta1, DEXP_INF, result_fs_d	# is FT an infinity?
	bne	ta2, zero, result_ft_d		# if FT is NAN, result is FT
	b	invalid_d			# infinity/infinity is invalid
1:
	bne	ta1, DEXP_INF, 1f		# is FT an infinity?
	bne	ta2, zero, result_ft_d		# if FT is NAN, result is FT
	move	t1, zero			# x / infinity is zero
	move	t2, zero
	b	result_fs_d
1:
	bne	t1, zero, 2f			# is FS zero?
	bne	t2, zero, 1f
	bne	ta1, zero, result_fs_d		# FS=zero, is FT zero?
	beq	ta2, zero, invalid_d		# 0 / 0
	b	result_fs_d			# result = zero
1:
	jal	renorm_fs_d
	b	3f
2:
	subu	t1, t1, DEXP_BIAS		# unbias FS exponent
	or	t2, t2, DIMPL_ONE		# set implied one bit
3:
	bne	ta1, zero, 2f			# is FT zero?
	bne	ta2, zero, 1f
	or	a1, a1, FPC_EXCEPTION_DIV0 | FPC_STICKY_DIV0
	and	v0, a1, FPC_ENABLE_DIV0	# trap enabled?
	bne	v0, zero, fpe_trap
	ctc1	a1, FPC_CSR			# Save exceptions
	li	t1, DEXP_INF			# result is infinity
	move	t2, zero
	b	result_fs_d
1:
	jal	renorm_ft_d
	b	3f
2:
	subu	ta1, ta1, DEXP_BIAS		# unbias FT exponent
	or	ta2, ta2, DIMPL_ONE		# set implied one bit
3:
	subu	t1, t1, ta1			# compute exponent
	subu	t1, t1, 3			# compensate for result position
	li	v0, DFRAC_BITS+3		# number of bits to divide
	move	t8, t2				# init dividend
	move	t2, zero			# init result
1:
	bltu	t8, ta2, 3f			# is dividend >= divisor?
2:
	dsubu	t8, t8, ta2			# subtract divisor from dividend
	or	t2, t2, 1			# remember that we did
	bne	t8, zero, 3f			# if not done, continue
	dsll	t2, t2, v0			# shift upper part
	b	norm_d
3:
	dsll	t8, t8, 1			# shift dividend
	dsll	t2, t2, 1			# shift result
	subu	v0, v0, 1			# are we done?
	bne	v0, zero, 1b			# no, continue
	b	norm_d

/*
 * Single precision absolute value.
 */
abs_s:
	jal	get_fs_s
	move	t0, zero			# set sign positive
	b	result_fs_s

/*
 * Double precision absolute value.
 */
abs_d:
	jal	get_fs_d
	move	t0, zero			# set sign positive
	b	result_fs_d

/*
 * Single precision move.
 */
mov_s:
	jal	get_fs_s
	b	result_fs_s

/*
 * Double precision move.
 */
mov_d:
	jal	get_fs_d
	b	result_fs_d

/*
 * Single precision negate.
 */
neg_s:
	jal	get_fs_s
	xor	t0, t0, 1			# reverse sign
	b	result_fs_s

/*
 * Double precision negate.
 */
neg_d:
	jal	get_fs_d
	xor	t0, t0, 1			# reverse sign
	b	result_fs_d

/*
 * Convert double to single.
 */
cvt_s_d:
	jal	get_fs_d
	bne	t1, DEXP_INF, 1f		# is FS an infinity?
	li	t1, SEXP_INF			# convert to single
	dsll	t2, t2, 3			# convert D fraction to S
	b	result_fs_s
1:
	bne	t1, zero, 2f			# is FS zero?
	beq	t2, zero, result_fs_s		# result=0
	jal	renorm_fs_d
	subu	t1, t1, 3			# correct exp for shift below
	b	3f
2:
	subu	t1, t1, DEXP_BIAS		# unbias exponent
	or	t2, t2, DIMPL_ONE		# add implied one bit
3:
	dsll	t2, t2, 3			# convert D fraction to S
	b	norm_noshift_s

/*
 * Convert long integer to single.
 */
cvt_s_l:
	jal	get_fs_long
	b	cvt_s_int
/*
 * Convert integer to single.
 */
cvt_s_w:
	jal	get_fs_int
cvt_s_int:
	bne	t2, zero, 1f			# check for zero
	move	t1, zero
	b	result_fs_s
/*
 * Find out how many leading zero bits are in t2 and put in t9.
 */
1:
	move	v0, t2
	move	t9, zero
	dsrl	v1, v0, 32
	bne	v1, zero, 1f
	addu	t9, 32
	dsll	v0, 32
1:
	dsrl	v1, v0, 16
	bne	v1, zero, 1f
	addu	t9, 16
	dsll	v0, 16
1:
	dsrl	v1, v0, 24
	bne	v1, zero, 1f
	addu	t9, 8
	dsll	v0, 8
1:
	dsrl	v1, v0, 28
	bne	v1, zero, 1f
	addu	t9, 4
	dsll	v0, 4
1:
	dsrl	v1, v0, 30
	bne	v1, zero, 1f
	addu	t9, 2
	dsll	v0, 2
1:
	dsrl	v1, v0, 31
	bne	v1, zero, 1f
	addu	t9, 1
/*
 * Now shift t2 the correct number of bits.
 */
1:
	subu	t9, SLEAD_ZEROS			# dont count leading zeros
	li	t1, 23+32			# init exponent
	subu	t1, t1, t9			# compute exponent
	beq	t9, zero, 1f
	li	v0, 32
	blt	t9, zero, 2f			# if shift < 0, shift right
	subu	v0, v0, t9
	sll	t2, t2, t9			# shift left
1:
	add	t1, t1, SEXP_BIAS		# bias exponent
	and	t2, t2, ~SIMPL_ONE		# clear implied one bit
	b	result_fs_s
2:
	negu	t9				# shift right by t9
	subu	v0, v0, t9
	sll	t8, t2, v0			# save bits shifted out
	srl	t2, t2, t9
	b	norm_noshift_s

/*
 * Convert single to double.
 */
cvt_d_s:
	jal	get_fs_s
	dsll	t2, 32
	bne	t1, SEXP_INF, 1f		# is FS an infinity?
	li	t1, DEXP_INF			# convert to double
	b	result_fs_d
1:
	bne	t1, zero, 2f			# is FS denormalized or zero?
	beq	t2, zero, result_fs_d		# is FS zero?
	jal	renorm_fs_s
	move	t8, zero
	b	norm_d
2:
	addu	t1, t1, DEXP_BIAS - SEXP_BIAS	# bias exponent correctly
	dsrl	t2, t2, 3
	b	result_fs_d

/*
 * Convert long integer to double.
 */
cvt_d_l:
	jal	get_fs_long
	b	cvt_d_int
/*
 * Convert integer to double.
 */
cvt_d_w:
	jal	get_fs_int
cvt_d_int:
	bne	t2, zero, 1f			# check for zero
	move	t1, zero			# result=0
	b	result_fs_d
/*
 * Find out how many leading zero bits are in t2 and put in t9.
 */
1:
	move	v0, t2
	move	t9, zero
	dsrl	v1, v0, 32
	bne	v1, zero, 1f
	addu	t9, 32
	dsll	v0, 32
1:
	dsrl	v1, v0, 16
	bne	v1, zero, 1f
	addu	t9, 16
	dsll	v0, 16
1:
	dsrl	v1, v0, 24
	bne	v1, zero, 1f
	addu	t9, 8
	dsll	v0, 8
1:
	dsrl	v1, v0, 28
	bne	v1, zero, 1f
	addu	t9, 4
	dsll	v0, 4
1:
	dsrl	v1, v0, 30
	bne	v1, zero, 1f
	addu	t9, 2
	dsll	v0, 2
1:
	dsrl	v1, v0, 31
	bne	v1, zero, 1f
	addu	t9, 1
/*
 * Now shift t2 the correct number of bits.
 */
1:
	subu	t9, t9, DLEAD_ZEROS		# dont count leading zeros
	li	t1, DEXP_BIAS + 20		# init exponent
	subu	t1, t1, t9			# compute exponent
	beq	t9, zero, 1f
	li	v0, 64
	blt	t9, zero, 2f			# if shift < 0, shift right
	subu	v0, v0, t9
	dsll	t2, t2, t9			# shift left
1:
	and	t2, t2, ~DIMPL_ONE		# clear implied one bit
	b	result_fs_d
2:
	negu	t9				# shift right by t9
	subu	v0, v0, t9
	dsrl	t2, t2, t9
	and	t2, t2, ~DIMPL_ONE		# clear implied one bit
	b	result_fs_d

/*
 * Convert single to integer with specific rounding.
 */
round_w_s:
	li	t3, FPC_ROUND_RN
	b	do_cvt_w_s
trunc_w_s:
	li	t3, FPC_ROUND_RZ
	b	do_cvt_w_s
ceil_w_s:
	li	t3, FPC_ROUND_RP
	b	do_cvt_w_s
floor_w_s:
	li	t3, FPC_ROUND_RM
	b	do_cvt_w_s

/*
 * Convert single to integer.
 */
cvt_w_s:
	and	t3, a1, FPC_ROUNDING_BITS	# get rounding mode
do_cvt_w_s:
	jal	get_fs_s
	bne	t1, SEXP_INF, 1f		# is FS an infinity?
	bne	t2, zero, invalid_w		# invalid conversion
1:
	bne	t1, zero, 1f			# is FS zero?
	beq	t2, zero, result_fs_w		# result is zero
	move	t2, zero			# result is an inexact zero
	b	inexact_w
1:
	subu	t1, t1, SEXP_BIAS		# unbias exponent
	or	t2, t2, SIMPL_ONE		# add implied one bit
	dsll	t2, t2, 32 - 3			# convert S fraction to D
	b	cvt_w

/*
 * Convert single to integer with specific rounding.
 */
round_w_d:
	li	t3, FPC_ROUND_RN
	b	do_cvt_w_d
trunc_w_d:
	li	t3, FPC_ROUND_RZ
	b	do_cvt_w_d
ceil_w_d:
	li	t3, FPC_ROUND_RP
	b	do_cvt_w_d
floor_w_d:
	li	t3, FPC_ROUND_RM
	b	do_cvt_w_d

/*
 * Convert double to integer.
 */
cvt_w_d:
	and	t3, a1, FPC_ROUNDING_BITS	# get rounding mode
do_cvt_w_d:
	jal	get_fs_d
	bne	t1, DEXP_INF, 1f		# is FS an infinity?
	bne	t2, zero, invalid_w		# invalid conversion
1:
	bne	t1, zero, 2f			# is FS zero?
	beq	t2, zero, result_fs_w		# result is zero
	move	t2, zero			# result is an inexact zero
	b	inexact_w
2:
	subu	t1, t1, DEXP_BIAS		# unbias exponent
	or	t2, t2, DIMPL_ONE		# add implied one bit
cvt_w:
	blt	t1, WEXP_MIN, underflow_w	# is exponent too small?
	li	v0, WEXP_MAX+1
	bgt	t1, v0, overflow_w		# is exponent too large?
	bne	t1, v0, 1f			# special check for INT_MIN
	beq	t0, zero, overflow_w		# if positive, overflow
	bne	t2, DIMPL_ONE, overflow_w
	li	t2, INT_MIN			# result is INT_MIN
	b	result_fs_w
1:
	subu	v0, t1, 20			# compute amount to shift
	beq	v0, zero, 2f			# is shift needed?
	li	v1, 64
	blt	v0, zero, 1f			# if shift < 0, shift right
	subu	v1, v1, v0			# shift left
	dsll	t2, t2, v0
	b	2f
1:
	negu	v0				# shift right by v0
	subu	v1, v1, v0
	dsll	t8, t2, v1			# save bits shifted out
	sltu	t8, zero, t8			# dont lose any ones
	dsrl	t2, t2, v0
/*
 * round (t0 is sign, t2:63-32 is integer part, t2:31-0 is fractional part).
 */
2:
	beq	t3, FPC_ROUND_RN, 3f		# round to nearest
	beq	t3, FPC_ROUND_RZ, 5f		# round to zero (truncate)
	beq	t3, FPC_ROUND_RP, 1f		# round to +infinity
	beq	t0, zero, 5f			# if sign is positive, truncate
	b	2f
1:
	bne	t0, zero, 5f			# if sign is negative, truncate
2:
	daddu	t2, t2, GUARDBIT		# add in fractional
	blt	t2, zero, overflow_w		# overflow?
	b	5f
3:
	daddu	t2, t2, GUARDBIT		# add in fractional
	blt	t2, zero, overflow_w		# overflow?
4:
	bne	v0, zero, 5f			# if rounded remainder is zero
	and	t2, 0xfffffffe00000000		#  clear LSB (round to nearest)
5:
	beq	t0, zero, 1f			# result positive?
	negu	t2				# convert to negative integer
1:
	dsll	v0, 32				# save fraction
	dsrl	t2, 32				# shift out fractional part
	beq	v0, zero, result_fs_w		# is result exact?
/*
 * Handle inexact exception.
 */
inexact_w:
	or	a1, a1, FPC_EXCEPTION_INEXACT | FPC_STICKY_INEXACT
	and	v0, a1, FPC_ENABLE_INEXACT
	bne	v0, zero, fpe_trap
	ctc1	a1, FPC_CSR		# save exceptions
	b	result_fs_w

/*
 * Conversions to integer which overflow will trap (if enabled),
 * or generate an inexact trap (if enabled),
 * or generate an invalid exception.
 */
overflow_w:
	or	a1, a1, FPC_EXCEPTION_OVERFLOW | FPC_STICKY_OVERFLOW
	and	v0, a1, FPC_ENABLE_OVERFLOW
	bne	v0, zero, fpe_trap
	and	v0, a1, FPC_ENABLE_INEXACT
	bne	v0, zero, inexact_w		# inexact traps enabled?
	b	invalid_w

/*
 * Conversions to integer which underflow will trap (if enabled),
 * or generate an inexact trap (if enabled),
 * or generate an invalid exception.
 */
underflow_w:
	or	a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW
	and	v0, a1, FPC_ENABLE_UNDERFLOW
	bne	v0, zero, fpe_trap
	and	v0, a1, FPC_ENABLE_INEXACT
	bne	v0, zero, inexact_w		# inexact traps enabled?
	b	invalid_w

/*
 * Compare single.
 */
cmp_s:
	jal	get_cmp_s
	bne	t1, SEXP_INF, 1f		# is FS an infinity?
	bne	t2, zero, unordered		# FS is a NAN
1:
	bne	ta1, SEXP_INF, 2f		# is FT an infinity?
	bne	ta2, zero, unordered		# FT is a NAN
2:
	sll	t1, t1, 23			# reassemble exp & frac
	or	t1, t1, t2
	sll	ta1, ta1, 23			# reassemble exp & frac
	or	ta1, ta1, ta2
	beq	t0, zero, 1f			# is FS positive?
	negu	t1
1:
	beq	ta0, zero, 1f			# is FT positive?
	negu	ta1
1:
	li	v0, COND_LESS
	blt	t1, ta1, test_cond		# is FS < FT?
	li	v0, COND_EQUAL
	beq	t1, ta1, test_cond		# is FS == FT?
	move	v0, zero			# FS > FT
	b	test_cond

/*
 * Compare double.
 */
cmp_d:
	jal	get_cmp_d
	bne	t1, DEXP_INF, 1f		# is FS an infinity?
	bne	t2, zero, unordered		# FS is a NAN
1:
	bne	ta1, DEXP_INF, 2f		# is FT an infinity?
	bne	ta2, zero, unordered		# FT is a NAN
2:
	dsll	t1, t1, 52			# reassemble exp & frac
	or	t1, t1, t2
	dsll	ta1, ta1, 52			# reassemble exp & frac
	or	ta1, ta1, ta2
	beq	t0, zero, 1f			# is FS positive?
	dnegu	t1				# negate t1
1:
	beq	ta0, zero, 1f			# is FT positive?
	dnegu	ta1
1:
	li	v0, COND_LESS
	blt	t1, ta1, test_cond		# is FS(MSW) < FT(MSW)?
	li	v0, COND_EQUAL
	beq	t1, ta1, test_cond		# is FS(LSW) == FT(LSW)?
	move	v0, zero			# FS > FT
test_cond:
	and	v0, v0, a0			# condition match instruction?
set_cond:
	bne	v0, zero, 1f
	and	a1, a1, ~FPC_COND_BIT	# clear condition bit
	b	2f
1:
	or	a1, a1, FPC_COND_BIT	# set condition bit
2:
	ctc1	a1, FPC_CSR		# save condition bit
	b	done

unordered:
	and	v0, a0, COND_UNORDERED		# this cmp match unordered?
	bne	v0, zero, 1f
	and	a1, a1, ~FPC_COND_BIT	# clear condition bit
	b	2f
1:
	or	a1, a1, FPC_COND_BIT	# set condition bit
2:
	and	v0, a0, COND_SIGNAL
	beq	v0, zero, 1f			# is this a signaling cmp?
	or	a1, a1, FPC_EXCEPTION_INVALID | FPC_STICKY_INVALID
	and	v0, a1, FPC_ENABLE_INVALID
	bne	v0, zero, fpe_trap
1:
	ctc1	a1, FPC_CSR		# save condition bit
	b	done

/*
 * Determine the amount to shift the fraction in order to restore the
 * normalized position. After that, round and handle exceptions.
 */
norm_s:
	move	v0, t2
	move	t9, zero			# t9 = num of leading zeros
	bne	t2, zero, 1f
	move	v0, t8
	addu	t9, 32
1:
	srl	v1, v0, 16
	bne	v1, zero, 1f
	addu	t9, 16
	sll	v0, 16
1:
	srl	v1, v0, 24
	bne	v1, zero, 1f
	addu	t9, 8
	sll	v0, 8
1:
	srl	v1, v0, 28
	bne	v1, zero, 1f
	addu	t9, 4
	sll	v0, 4
1:
	srl	v1, v0, 30
	bne	v1, zero, 1f
	addu	t9, 2
	sll	v0, 2
1:
	srl	v1, v0, 31
	bne	v1, zero, 1f
	addu	t9, 1
/*
 * Now shift t2,t8 the correct number of bits.
 */
1:
	subu	t9, t9, SLEAD_ZEROS		# dont count leading zeros
	subu	t1, t1, t9			# adjust the exponent
	beq	t9, zero, norm_noshift_s
	li	v1, 32
	blt	t9, zero, 1f			# if shift < 0, shift right
	subu	v1, v1, t9
	sll	t2, t2, t9			# shift t2,t8 left
	srl	v0, t8, v1			# save bits shifted out
	or	t2, t2, v0
	sll	t8, t8, t9
	b	norm_noshift_s
1:
	negu	t9				# shift t2,t8 right by t9
	subu	v1, v1, t9
	sll	v0, t8, v1			# save bits shifted out
	sltu	v0, zero, v0			# be sure to save any one bits
	srl	t8, t8, t9
	or	t8, t8, v0
	sll	v0, t2, v1			# save bits shifted out
	or	t8, t8, v0
	srl	t2, t2, t9
norm_noshift_s:
	move	ta1, t1				# save unrounded exponent
	move	ta2, t2				# save unrounded fraction
	and	v0, a1, FPC_ROUNDING_BITS	# get rounding mode
	beq	v0, FPC_ROUND_RN, 3f	# round to nearest
	beq	v0, FPC_ROUND_RZ, 5f	# round to zero (truncate)
	beq	v0, FPC_ROUND_RP, 1f	# round to +infinity
	beq	t0, zero, 5f			# if sign is positive, truncate
	b	2f
1:
	bne	t0, zero, 5f			# if sign is negative, truncate
2:
	beq	t8, zero, 5f			# if exact, continue
	addu	t2, t2, 1			# add rounding bit
	bne	t2, SIMPL_ONE<<1, 5f		# need to adjust exponent?
	addu	t1, t1, 1			# adjust exponent
	srl	t2, t2, 1			# renormalize fraction
	b	5f
3:
	li	v0, GUARDBIT			# load guard bit for rounding
	addu	v0, v0, t8			# add remainder
	sltu	v1, v0, t8			# compute carry out
	beq	v1, zero, 4f			# if no carry, continue
	addu	t2, t2, 1			# add carry to result
	bne	t2, SIMPL_ONE<<1, 4f		# need to adjust exponent?
	addu	t1, t1, 1			# adjust exponent
	srl	t2, t2, 1			# renormalize fraction
4:
	bne	v0, zero, 5f			# if rounded remainder is zero
	and	t2, t2, ~1			#  clear LSB (round to nearest)
5:
	bgt	t1, SEXP_MAX, overflow_s	# overflow?
	blt	t1, SEXP_MIN, underflow_s	# underflow?
	bne	t8, zero, inexact_s		# is result inexact?
	addu	t1, t1, SEXP_BIAS		# bias exponent
	and	t2, t2, ~SIMPL_ONE		# clear implied one bit
	b	result_fs_s

/*
 * Handle inexact exception.
 */
inexact_s:
	addu	t1, t1, SEXP_BIAS		# bias exponent
	and	t2, t2, ~SIMPL_ONE		# clear implied one bit
inexact_nobias_s:
	jal	set_fd_s			# save result
	or	a1, a1, FPC_EXCEPTION_INEXACT | FPC_STICKY_INEXACT
	and	v0, a1, FPC_ENABLE_INEXACT
	bne	v0, zero, fpe_trap
	ctc1	a1, FPC_CSR		# save exceptions
	b	done

/*
 * Overflow will trap (if enabled),
 * or generate an inexact trap (if enabled),
 * or generate an infinity.
 */
overflow_s:
	or	a1, a1, FPC_EXCEPTION_OVERFLOW | FPC_STICKY_OVERFLOW
	and	v0, a1, FPC_ENABLE_OVERFLOW
	beq	v0, zero, 1f
	subu	t1, t1, 192			# bias exponent
	and	t2, t2, ~SIMPL_ONE		# clear implied one bit
	jal	set_fd_s			# save result
	b	fpe_trap
1:
	and	v0, a1, FPC_ROUNDING_BITS	# get rounding mode
	beq	v0, FPC_ROUND_RN, 3f	# round to nearest
	beq	v0, FPC_ROUND_RZ, 1f	# round to zero (truncate)
	beq	v0, FPC_ROUND_RP, 2f	# round to +infinity
	bne	t0, zero, 3f
1:
	li	t1, SEXP_MAX			# result is max finite
	li	t2, 0x007fffff
	b	inexact_s
2:
	bne	t0, zero, 1b
3:
	li	t1, SEXP_MAX + 1		# result is infinity
	move	t2, zero
	b	inexact_s

/*
 * In this implementation, "tininess" is detected "after rounding" and
 * "loss of accuracy" is detected as "an inexact result".
 */
underflow_s:
	and	v0, a1, FPC_ENABLE_UNDERFLOW
	beq	v0, zero, 1f
/*
 * Underflow is enabled so compute the result and trap.
 */
	addu	t1, t1, 192			# bias exponent
	and	t2, t2, ~SIMPL_ONE		# clear implied one bit
	jal	set_fd_s			# save result
	or	a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW
	b	fpe_trap
/*
 * Underflow is not enabled so compute the result,
 * signal inexact result (if it is) and trap (if enabled).
 */
1:
	move	t1, ta1				# get unrounded exponent
	move	t2, ta2				# get unrounded fraction
	li	t9, SEXP_MIN			# compute shift amount
	subu	t9, t9, t1			# shift t2,t8 right by t9
	blt	t9, SFRAC_BITS+2, 3f		# shift all the bits out?
	move	t1, zero			# result is inexact zero
	move	t2, zero
	or	a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW
/*
 * Now round the zero result.
 * Only need to worry about rounding to +- infinity when the sign matches.
 */
	and	v0, a1, FPC_ROUNDING_BITS	# get rounding mode
	beq	v0, FPC_ROUND_RN, inexact_nobias_s	# round to nearest
	beq	v0, FPC_ROUND_RZ, inexact_nobias_s	# round to zero
	beq	v0, FPC_ROUND_RP, 1f	# round to +infinity
	beq	t0, zero, inexact_nobias_s	# if sign is positive, truncate
	b	2f
1:
	bne	t0, zero, inexact_nobias_s	# if sign is negative, truncate
2:
	addu	t2, t2, 1			# add rounding bit
	b	inexact_nobias_s
3:
	li	v1, 32
	subu	v1, v1, t9
	sltu	v0, zero, t8			# be sure to save any one bits
	sll	t8, t2, v1			# save bits shifted out
	or	t8, t8, v0			# include sticky bits
	srl	t2, t2, t9
/*
 * Now round the denormalized result.
 */
	and	v0, a1, FPC_ROUNDING_BITS	# get rounding mode
	beq	v0, FPC_ROUND_RN, 3f	# round to nearest
	beq	v0, FPC_ROUND_RZ, 5f	# round to zero (truncate)
	beq	v0, FPC_ROUND_RP, 1f	# round to +infinity
	beq	t0, zero, 5f			# if sign is positive, truncate
	b	2f
1:
	bne	t0, zero, 5f			# if sign is negative, truncate
2:
	beq	t8, zero, 5f			# if exact, continue
	addu	t2, t2, 1			# add rounding bit
	b	5f
3:
	li	v0, GUARDBIT			# load guard bit for rounding
	addu	v0, v0, t8			# add remainder
	sltu	v1, v0, t8			# compute carry out
	beq	v1, zero, 4f			# if no carry, continue
	addu	t2, t2, 1			# add carry to result
4:
	bne	v0, zero, 5f			# if rounded remainder is zero
	and	t2, t2, ~1			#  clear LSB (round to nearest)
5:
	move	t1, zero			# denorm or zero exponent
	jal	set_fd_s			# save result
	beq	t8, zero, done			# check for exact result
	or	a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW
	or	a1, a1, FPC_EXCEPTION_INEXACT | FPC_STICKY_INEXACT
	and	v0, a1, FPC_ENABLE_INEXACT
	bne	v0, zero, fpe_trap
	ctc1	a1, FPC_CSR		# save exceptions
	b	done

/*
 * Determine the amount to shift the fraction in order to restore the
 * normalized position. After that, round and handle exceptions.
 */
norm_d:
	move	v0, t2
	move	t9, zero			# t9 = num of leading zeros
	dsrl	v1, v0, 32
	bne	v1, zero, 1f
	addu	t9, 32
	dsll	v0, 32
1:
	dsrl	v1, v0, 16
	bne	v1, zero, 1f
	addu	t9, 16
	dsll	v0, 16
1:
	dsrl	v1, v0, 24
	bne	v1, zero, 1f
	addu	t9, 8
	dsll	v0, 8
1:
	dsrl	v1, v0, 28
	bne	v1, zero, 1f
	addu	t9, 4
	dsll	v0, 4
1:
	dsrl	v1, v0, 30
	bne	v1, zero, 1f
	addu	t9, 2
	dsll	v0, 2
1:
	dsrl	v1, v0, 31
	bne	v1, zero, 1f
	addu	t9, 1
/*
 * Now shift t2,t8 the correct number of bits.
 */
1:
	subu	t9, t9, DLEAD_ZEROS		# dont count leading zeros
	subu	t1, t1, t9			# adjust the exponent
	beq	t9, zero, norm_noshift_d
	li	v1, 64
	blt	t9, zero, 2f			# if shift < 0, shift right
	subu	v1, v1, t9
	dsll	t2, t2, t9			# shift left by t9
	dsrl	v0, t8, v1			# save bits shifted out
	or	t2, t2, v0
	dsll	t8, t8, t9
	b	norm_noshift_d
2:
	negu	t9				# shift right by t9
	subu	v1, v1, t9			#  (known to be < 32 bits)
	dsll	v0, t8, v1			# save bits shifted out
	sltu	v0, zero, v0			# be sure to save any one bits
	dsrl	t8, t8, t9
	or	t8, t8, v0
	dsll	v0, t2, v1			# save bits shifted out
	or	t8, t8, v0
	dsrl	t2, t2, t9
norm_noshift_d:
	move	ta1, t1				# save unrounded exponent
	move	ta2, t2				# save unrounded fraction (MS)
	and	v0, a1, FPC_ROUNDING_BITS	# get rounding mode
	beq	v0, FPC_ROUND_RN, 3f	# round to nearest
	beq	v0, FPC_ROUND_RZ, 5f	# round to zero (truncate)
	beq	v0, FPC_ROUND_RP, 1f	# round to +infinity
	beq	t0, zero, 5f			# if sign is positive, truncate
	b	2f
1:
	bne	t0, zero, 5f			# if sign is negative, truncate
2:
	beq	t8, zero, 5f			# if exact, continue
	daddu	t2, t2, 1			# add rounding bit
	bne	t2, DIMPL_ONE<<1, 5f		# need to adjust exponent?
	addu	t1, t1, 1			# adjust exponent
	dsrl	t2, t2, 1			# renormalize fraction
	b	5f
3:
	dli	v0, DGUARDBIT			# load guard bit for rounding
	addu	v0, v0, t8			# add remainder
	sltu	v1, v0, t8			# compute carry out
	beq	v1, zero, 4f			# branch if no carry
	daddu	t2, t2, 1			# add carry to result
	bne	t2, DIMPL_ONE<<1, 4f		# need to adjust exponent?
	addu	t1, t1, 1			# adjust exponent
	srl	t2, t2, 1			# renormalize fraction
4:
	bne	v0, zero, 5f			# if rounded remainder is zero
	and	t2, t2, ~1			#  clear LSB (round to nearest)
5:
	bgt	t1, DEXP_MAX, overflow_d	# overflow?
	blt	t1, DEXP_MIN, underflow_d	# underflow?
	bne	t8, zero, inexact_d		# is result inexact?
	addu	t1, t1, DEXP_BIAS		# bias exponent
	and	t2, t2, ~DIMPL_ONE		# clear implied one bit
	b	result_fs_d

/*
 * Handle inexact exception.
 */
inexact_d:
	addu	t1, t1, DEXP_BIAS		# bias exponent
	and	t2, t2, ~DIMPL_ONE		# clear implied one bit
inexact_nobias_d:
	jal	set_fd_d			# save result
	or	a1, a1, FPC_EXCEPTION_INEXACT | FPC_STICKY_INEXACT
	and	v0, a1, FPC_ENABLE_INEXACT
	bne	v0, zero, fpe_trap
	ctc1	a1, FPC_CSR		# save exceptions
	b	done

/*
 * Overflow will trap (if enabled),
 * or generate an inexact trap (if enabled),
 * or generate an infinity.
 */
overflow_d:
	or	a1, a1, FPC_EXCEPTION_OVERFLOW | FPC_STICKY_OVERFLOW
	and	v0, a1, FPC_ENABLE_OVERFLOW
	beq	v0, zero, 1f
	subu	t1, t1, 1536			# bias exponent
	and	t2, t2, ~DIMPL_ONE		# clear implied one bit
	jal	set_fd_d			# save result
	b	fpe_trap
1:
	and	v0, a1, FPC_ROUNDING_BITS	# get rounding mode
	beq	v0, FPC_ROUND_RN, 3f	# round to nearest
	beq	v0, FPC_ROUND_RZ, 1f	# round to zero (truncate)
	beq	v0, FPC_ROUND_RP, 2f	# round to +infinity
	bne	t0, zero, 3f
1:
	li	t1, DEXP_MAX			# result is max finite
	dli	t2, 0x000fffffffffffff
	b	inexact_d
2:
	bne	t0, zero, 1b
3:
	li	t1, DEXP_MAX + 1		# result is infinity
	move	t2, zero
	b	inexact_d

/*
 * In this implementation, "tininess" is detected "after rounding" and
 * "loss of accuracy" is detected as "an inexact result".
 */
underflow_d:
	and	v0, a1, FPC_ENABLE_UNDERFLOW
	beq	v0, zero, 1f
/*
 * Underflow is enabled so compute the result and trap.
 */
	addu	t1, t1, 1536			# bias exponent
	and	t2, t2, ~DIMPL_ONE		# clear implied one bit
	jal	set_fd_d			# save result
	or	a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW
	b	fpe_trap
/*
 * Underflow is not enabled so compute the result,
 * signal inexact result (if it is) and trap (if enabled).
 */
1:
	move	t1, ta1				# get unrounded exponent
	move	t2, ta2				# get unrounded fraction (MS)
	li	t9, DEXP_MIN			# compute shift amount
	subu	t9, t9, t1			# shift t2,t8 right by t9
	blt	t9, DFRAC_BITS+2, 3f		# shift all the bits out?
	move	t1, zero			# result is inexact zero
	move	t2, zero
	or	a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW
/*
 * Now round the zero result.
 * Only need to worry about rounding to +- infinity when the sign matches.
 */
	and	v0, a1, FPC_ROUNDING_BITS	# get rounding mode
	beq	v0, FPC_ROUND_RN, inexact_nobias_d	# round to nearest
	beq	v0, FPC_ROUND_RZ, inexact_nobias_d	# round to zero
	beq	v0, FPC_ROUND_RP, 1f	# round to +infinity
	beq	t0, zero, inexact_nobias_d	# if sign is positive, truncate
	b	2f
1:
	bne	t0, zero, inexact_nobias_d	# if sign is negative, truncate
2:
	daddu	t2, t2, 1			# add rounding bit
	b	inexact_nobias_d
3:
	li	v1, 64
	subu	v1, v1, t9
	sltu	v0, zero, t8			# be sure to save any one bits
	dsll	t8, t2, v1			# save bits shifted out
	or	t8, t8, v0			# include sticky bits
	dsrl	t2, t2, t9
/*
 * Now round the denormalized result.
 */
	and	v0, a1, FPC_ROUNDING_BITS	# get rounding mode
	beq	v0, FPC_ROUND_RN, 3f	# round to nearest
	beq	v0, FPC_ROUND_RZ, 5f	# round to zero (truncate)
	beq	v0, FPC_ROUND_RP, 1f	# round to +infinity
	beq	t0, zero, 5f			# if sign is positive, truncate
	b	2f
1:
	bne	t0, zero, 5f			# if sign is negative, truncate
2:
	beq	t8, zero, 5f			# if exact, continue
	daddu	t2, t2, 1			# add rounding bit
	b	5f
3:
	dli	v0, DGUARDBIT			# load guard bit for rounding
	daddu	v0, v0, t8			# add remainder
	sltu	v1, v0, t8			# compute carry out
	beq	v1, zero, 4f			# if no carry, continue
	daddu	t2, t2, 1			# add carry
4:
	bne	v0, zero, 5f			# if rounded remainder is zero
	and	t2, t2, ~1			#  clear LSB (round to nearest)
5:
	move	t1, zero			# denorm or zero exponent
	jal	set_fd_d			# save result
	beq	t8, zero, done			# check for exact result
	or	a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW
	or	a1, a1, FPC_EXCEPTION_INEXACT | FPC_STICKY_INEXACT
	and	v0, a1, FPC_ENABLE_INEXACT
	bne	v0, zero, fpe_trap
	ctc1	a1, FPC_CSR		# save exceptions
	b	done

/*
 * Signal an invalid operation if the trap is enabled; otherwise,
 * the result is a quiet NAN.
 */
invalid_s:					# trap invalid operation
	or	a1, a1, FPC_EXCEPTION_INVALID | FPC_STICKY_INVALID
	and	v0, a1, FPC_ENABLE_INVALID
	bne	v0, zero, fpe_trap
	ctc1	a1, FPC_CSR		# save exceptions
	move	t0, zero			# result is a quiet NAN
	li	t1, SEXP_INF
	li	t2, SQUIET_NAN
	jal	set_fd_s			# save result (in t0,t1,t2)
	b	done

/*
 * Signal an invalid operation if the trap is enabled; otherwise,
 * the result is a quiet NAN.
 */
invalid_d:					# trap invalid operation
	or	a1, a1, FPC_EXCEPTION_INVALID | FPC_STICKY_INVALID
	and	v0, a1, FPC_ENABLE_INVALID
	bne	v0, zero, fpe_trap
	ctc1	a1, FPC_CSR		# save exceptions
	move	t0, zero			# result is a quiet NAN
	li	t1, DEXP_INF
	dli	t2, DQUIET_NAN
	jal	set_fd_d			# save result (in t0,t1,t2)
	b	done

/*
 * Signal an invalid operation if the trap is enabled; otherwise,
 * the result is INT_MAX or INT_MIN.
 */
invalid_w:					# trap invalid operation
	or	a1, a1, FPC_EXCEPTION_INVALID | FPC_STICKY_INVALID
	and	v0, a1, FPC_ENABLE_INVALID
	bne	v0, zero, fpe_trap
	ctc1	a1, FPC_CSR			# save exceptions
	bne	t0, zero, 1f
	li	t2, INT_MAX			# result is INT_MAX
	b	result_fs_w
1:
	li	t2, INT_MIN			# result is INT_MIN
	b	result_fs_w

/*
 * Trap if the hardware should have handled this case.
 */
fpe_trap:
	move	a2, a1				# code = FP CSR
	ctc1	a1, FPC_CSR			# save exceptions
	li	v0, 1
	b	done_err

/*
 * Send an illegal instruction signal to the current process.
 */
ill:
	ctc1	a1, FPC_CSR			# save exceptions
	move	a2, a0				# code = FP instruction
	li	v0, 1
	b	done_err

result_ft_s:
	move	t0, ta0				# result is FT
	move	t1, ta1
	move	t2, ta2
result_fs_s:					# result is FS
	jal	set_fd_s			# save result (in t0,t1,t2)
	b	done

result_fs_w:
	jal	set_fd_word			# save result (in t2)
	b	done

result_ft_d:
	move	t0, ta0				# result is FT
	move	t1, ta1
	move	t2, ta2
result_fs_d:					# result is FS
	jal	set_fd_d			# save result (in t0,t1,t2)

done:
	li	v0, 0
done_err:
	PTR_L	ra, CF_RA_OFFS(sp)
	PTR_ADD	sp, sp, FRAMESZ(CF_SZ)
	j	ra
END(MipsEmulateFP)

/*----------------------------------------------------------------------------
 * get_fs_int --
 *
 *	Read (integer) the FS register (bits 15-11).
 *	This is an internal routine used by MipsEmulateFP only.
 *
 * Results:
 *	t0	contains the sign
 *	t2	contains the fraction
 *
 *----------------------------------------------------------------------------
 */
#define GET_FS_INT(n) \
	.rdata;				\
	.dword	get_fs_int_/**/n;	\
	.text;				\
get_fs_int_/**/n:			\
	mfc1	t2, $/**/n;		\
	b	get_fs_int_done

LEAF(get_fs_int, 0)
	srl	a3, a0, 11 - 3			# get FS field
	and	a3, a3, 0x1f << 3		# mask FS field
	ld	a3, get_fs_int_tbl(a3)		# switch on register number
	j	a3

	.rdata
get_fs_int_tbl:
	.text

	GET_FS_INT(f0)
	GET_FS_INT(f1)
	GET_FS_INT(f2)
	GET_FS_INT(f3)
	GET_FS_INT(f4)
	GET_FS_INT(f5)
	GET_FS_INT(f6)
	GET_FS_INT(f7)
	GET_FS_INT(f8)
	GET_FS_INT(f9)
	GET_FS_INT(f10)
	GET_FS_INT(f11)
	GET_FS_INT(f12)
	GET_FS_INT(f13)
	GET_FS_INT(f14)
	GET_FS_INT(f15)
	GET_FS_INT(f16)
	GET_FS_INT(f17)
	GET_FS_INT(f18)
	GET_FS_INT(f19)
	GET_FS_INT(f20)
	GET_FS_INT(f21)
	GET_FS_INT(f22)
	GET_FS_INT(f23)
	GET_FS_INT(f24)
	GET_FS_INT(f25)
	GET_FS_INT(f26)
	GET_FS_INT(f27)
	GET_FS_INT(f28)
	GET_FS_INT(f29)
	GET_FS_INT(f30)
	GET_FS_INT(f31)

get_fs_int_done:
	srl	t0, t2, 31		# init the sign bit
	bge	t2, zero, 1f
	negu	t2
	dsll	t2, 33
	dsrl	t2, 33
1:
	j	ra
END(get_fs_int)

/*----------------------------------------------------------------------------
 * get_fs_long --
 *
 *	Read (long integer) the FS register (bits 15-11).
 *	This is an internal routine used by MipsEmulateFP only.
 *
 * Results:
 *	t0	contains the sign
 *	t2	contains the fraction
 *
 *----------------------------------------------------------------------------
 */
#define GET_FS_LONG(n) \
	.rdata;				\
	.dword	get_fs_long_/**/n;	\
	.text;				\
get_fs_long_/**/n:			\
	dmfc1	t2, $/**/n;		\
	b	get_fs_long_done

LEAF(get_fs_long, 0)
	srl	a3, a0, 11 - 3			# get FS field
	and	a3, a3, 0x1f << 3		# mask FS field
	ld	a3, get_fs_long_tbl(a3)		# switch on register number
	j	a3

	.rdata
get_fs_long_tbl:
	.text

	GET_FS_LONG(f0)
	GET_FS_LONG(f1)
	GET_FS_LONG(f2)
	GET_FS_LONG(f3)
	GET_FS_LONG(f4)
	GET_FS_LONG(f5)
	GET_FS_LONG(f6)
	GET_FS_LONG(f7)
	GET_FS_LONG(f8)
	GET_FS_LONG(f9)
	GET_FS_LONG(f10)
	GET_FS_LONG(f11)
	GET_FS_LONG(f12)
	GET_FS_LONG(f13)
	GET_FS_LONG(f14)
	GET_FS_LONG(f15)
	GET_FS_LONG(f16)
	GET_FS_LONG(f17)
	GET_FS_LONG(f18)
	GET_FS_LONG(f19)
	GET_FS_LONG(f20)
	GET_FS_LONG(f21)
	GET_FS_LONG(f22)
	GET_FS_LONG(f23)
	GET_FS_LONG(f24)
	GET_FS_LONG(f25)
	GET_FS_LONG(f26)
	GET_FS_LONG(f27)
	GET_FS_LONG(f28)
	GET_FS_LONG(f29)
	GET_FS_LONG(f30)
	GET_FS_LONG(f31)

get_fs_long_done:
	dsrl	t0, t2, 63		# init the sign bit
	bge	t2, zero, 1f
	dnegu	t2
1:
	j	ra
END(get_fs_long)

/*----------------------------------------------------------------------------
 * get_ft_fs_s --
 *
 *	Read (single precision) the FT register (bits 20-16) and
 *	the FS register (bits 15-11) and break up into fields.
 *	This is an internal routine used by MipsEmulateFP only.
 *
 * Results:
 *	t0	contains the FS sign
 *	t1	contains the FS (biased) exponent
 *	t2	contains the FS fraction
 *	ta0	contains the FT sign
 *	ta1	contains the FT (biased) exponent
 *	ta2	contains the FT fraction
 *
 *----------------------------------------------------------------------------
 */
#define GET_FT_S(n) \
	.rdata;				\
	.dword	get_ft_s_/**/n;		\
	.text;				\
get_ft_s_/**/n:				\
	mfc1	ta0, $/**/n;		\
	b	get_ft_s_done

LEAF(get_ft_fs_s, 0)
	srl	a3, a0, 16 - 3			# get FT field
	and	a3, a3, 0x1f << 3		# mask FT field
	ld	a3, get_ft_s_tbl(a3)		# switch on register number
	j	a3

	.rdata
get_ft_s_tbl:
	.text

	GET_FT_S(f0)
	GET_FT_S(f1)
	GET_FT_S(f2)
	GET_FT_S(f3)
	GET_FT_S(f4)
	GET_FT_S(f5)
	GET_FT_S(f6)
	GET_FT_S(f7)
	GET_FT_S(f8)
	GET_FT_S(f9)
	GET_FT_S(f10)
	GET_FT_S(f11)
	GET_FT_S(f12)
	GET_FT_S(f13)
	GET_FT_S(f14)
	GET_FT_S(f15)
	GET_FT_S(f16)
	GET_FT_S(f17)
	GET_FT_S(f18)
	GET_FT_S(f19)
	GET_FT_S(f20)
	GET_FT_S(f21)
	GET_FT_S(f22)
	GET_FT_S(f23)
	GET_FT_S(f24)
	GET_FT_S(f25)
	GET_FT_S(f26)
	GET_FT_S(f27)
	GET_FT_S(f28)
	GET_FT_S(f29)
	GET_FT_S(f30)
	GET_FT_S(f31)

get_ft_s_done:
	srl	ta1, ta0, 23			# get exponent
	and	ta1, ta1, 0xFF
	and	ta2, ta0, 0x7FFFFF		# get fraction
	srl	ta0, ta0, 31			# get sign
	bne	ta1, SEXP_INF, 1f		# is it a signaling NAN?
	and	v0, ta2, SSIGNAL_NAN
	bne	v0, zero, invalid_s
1:
	/* fall through to get FS */

/*----------------------------------------------------------------------------
 * get_fs_s --
 *
 *	Read (single precision) the FS register (bits 15-11) and
 *	break up into fields.
 *	This is an internal routine used by MipsEmulateFP only.
 *
 * Results:
 *	t0	contains the sign
 *	t1	contains the (biased) exponent
 *	t2	contains the fraction
 *
 *----------------------------------------------------------------------------
 */
#define GET_FS_S(n) \
	.rdata;				\
	.dword	get_fs_s_/**/n;		\
	.text;				\
get_fs_s_/**/n:				\
	mfc1	t0, $/**/n;		\
	b	get_fs_s_done

ALEAF(get_fs_s)
	srl	a3, a0, 11 - 3			# get FS field
	and	a3, a3, 0x1f << 3		# mask FS field
	ld	a3, get_fs_s_tbl(a3)		# switch on register number
	j	a3

	.rdata
get_fs_s_tbl:
	.text

	GET_FS_S(f0)
	GET_FS_S(f1)
	GET_FS_S(f2)
	GET_FS_S(f3)
	GET_FS_S(f4)
	GET_FS_S(f5)
	GET_FS_S(f6)
	GET_FS_S(f7)
	GET_FS_S(f8)
	GET_FS_S(f9)
	GET_FS_S(f10)
	GET_FS_S(f11)
	GET_FS_S(f12)
	GET_FS_S(f13)
	GET_FS_S(f14)
	GET_FS_S(f15)
	GET_FS_S(f16)
	GET_FS_S(f17)
	GET_FS_S(f18)
	GET_FS_S(f19)
	GET_FS_S(f20)
	GET_FS_S(f21)
	GET_FS_S(f22)
	GET_FS_S(f23)
	GET_FS_S(f24)
	GET_FS_S(f25)
	GET_FS_S(f26)
	GET_FS_S(f27)
	GET_FS_S(f28)
	GET_FS_S(f29)
	GET_FS_S(f30)
	GET_FS_S(f31)

get_fs_s_done:
	srl	t1, t0, 23			# get exponent
	and	t1, t1, 0xFF
	and	t2, t0, 0x7FFFFF		# get fraction
	srl	t0, t0, 31			# get sign
	bne	t1, SEXP_INF, 1f		# is it a signaling NAN?
	and	v0, t2, SSIGNAL_NAN
	bne	v0, zero, invalid_s
1:
	j	ra
END(get_ft_fs_s)

/*----------------------------------------------------------------------------
 * get_ft_fs_d --
 *
 *	Read (double precision) the FT register (bits 20-16) and
 *	the FS register (bits 15-11) and break up into fields.
 *	This is an internal routine used by MipsEmulateFP only.
 *
 * Results:
 *	t0	contains the FS sign
 *	t1	contains the FS (biased) exponent
 *	t2	contains the FS fraction
 *	ta0	contains the FT sign
 *	ta1	contains the FT (biased) exponent
 *	ta2	contains the FT fraction
 *
 *----------------------------------------------------------------------------
 */
#define GET_FT_FS_D(n) \
	.rdata;				\
	.dword	get_ft_fs_d_/**/n;	\
	.text;				\
get_ft_fs_d_/**/n:			\
	dmfc1	ta2, $/**/n;		\
	b	get_ft_d_done

LEAF(get_ft_fs_d, 0)
	srl	a3, a0, 16 - 3			# get FT field
	and	a3, a3, 0x1f << 3		# mask FT field
	ld	a3, get_ft_d_tbl(a3)		# switch on register number
	j	a3

	.rdata
get_ft_d_tbl:
	.text

	GET_FT_FS_D(f0)
	GET_FT_FS_D(f1)
	GET_FT_FS_D(f2)
	GET_FT_FS_D(f3)
	GET_FT_FS_D(f4)
	GET_FT_FS_D(f5)
	GET_FT_FS_D(f6)
	GET_FT_FS_D(f7)
	GET_FT_FS_D(f8)
	GET_FT_FS_D(f9)
	GET_FT_FS_D(f10)
	GET_FT_FS_D(f11)
	GET_FT_FS_D(f12)
	GET_FT_FS_D(f13)
	GET_FT_FS_D(f14)
	GET_FT_FS_D(f15)
	GET_FT_FS_D(f16)
	GET_FT_FS_D(f17)
	GET_FT_FS_D(f18)
	GET_FT_FS_D(f19)
	GET_FT_FS_D(f20)
	GET_FT_FS_D(f21)
	GET_FT_FS_D(f22)
	GET_FT_FS_D(f23)
	GET_FT_FS_D(f24)
	GET_FT_FS_D(f25)
	GET_FT_FS_D(f26)
	GET_FT_FS_D(f27)
	GET_FT_FS_D(f28)
	GET_FT_FS_D(f29)
	GET_FT_FS_D(f30)
	GET_FT_FS_D(f31)

get_ft_d_done:
	dsrl	ta0, ta2, 63			# get sign
	dsrl	ta1, ta2, 52			# get exponent
	and	ta1, ta1, 0x7FF
	dsll	ta2, 12
	dsrl	ta2, 12				# get fraction
	bne	ta1, DEXP_INF, 1f		# is it a signaling NAN?
	and	v0, ta2, DSIGNAL_NAN
	bne	v0, zero, invalid_d
1:
	/* fall through to get FS */

/*----------------------------------------------------------------------------
 * get_fs_d --
 *
 *	Read (double precision) the FS register (bits 15-11) and
 *	break up into fields.
 *	This is an internal routine used by MipsEmulateFP only.
 *
 * Results:
 *	t0	contains the sign
 *	t1	contains the (biased) exponent
 *	t2	contains the fraction
 *
 *----------------------------------------------------------------------------
 */
#define GET_FS_D(n) \
	.rdata;				\
	.dword	get_fs_d_/**/n;		\
	.text;				\
get_fs_d_/**/n:				\
	dmfc1	t2, $/**/n;		\
	b	get_fs_d_done

ALEAF(get_fs_d)
	srl	a3, a0, 11 - 3			# get FS field
	and	a3, a3, 0x1f << 3		# mask FS field
	ld	a3, get_fs_d_tbl(a3)		# switch on register number
	j	a3

	.rdata
get_fs_d_tbl:
	.text

	GET_FS_D(f0)
	GET_FS_D(f1)
	GET_FS_D(f2)
	GET_FS_D(f3)
	GET_FS_D(f4)
	GET_FS_D(f5)
	GET_FS_D(f6)
	GET_FS_D(f7)
	GET_FS_D(f8)
	GET_FS_D(f9)
	GET_FS_D(f10)
	GET_FS_D(f11)
	GET_FS_D(f12)
	GET_FS_D(f13)
	GET_FS_D(f14)
	GET_FS_D(f15)
	GET_FS_D(f16)
	GET_FS_D(f17)
	GET_FS_D(f18)
	GET_FS_D(f19)
	GET_FS_D(f20)
	GET_FS_D(f21)
	GET_FS_D(f22)
	GET_FS_D(f23)
	GET_FS_D(f24)
	GET_FS_D(f25)
	GET_FS_D(f26)
	GET_FS_D(f27)
	GET_FS_D(f28)
	GET_FS_D(f29)
	GET_FS_D(f30)
	GET_FS_D(f31)

get_fs_d_done:
	dsrl	t0, t2, 63			# get sign
	dsrl	t1, t2, 52			# get exponent
	and	t1, t1, 0x7FF
	dsll	t2, 12
	dsrl	t2, 12				# get fraction
	bne	t1, DEXP_INF, 1f		# is it a signaling NAN?
	and	v0, t2, DSIGNAL_NAN
	bne	v0, zero, invalid_d
1:
	j	ra
END(get_ft_fs_d)

/*----------------------------------------------------------------------------
 * get_cmp_s --
 *
 *	Read (single precision) the FS register (bits 15-11) and
 *	the FT register (bits 20-16) and break up into fields.
 *	This is an internal routine used by MipsEmulateFP only.
 *
 * Results:
 *	t0	contains the sign
 *	t1	contains the (biased) exponent
 *	t2	contains the fraction
 *	ta0	contains the sign
 *	ta1	contains the (biased) exponent
 *	ta2	contains the fraction
 *
 *----------------------------------------------------------------------------
 */
#define CMP_FS_S(n) \
	.rdata;				\
	.dword	cmp_fs_s_/**/n;		\
	.text;				\
cmp_fs_s_/**/n:				\
	mfc1	t0, $/**/n;		\
	b	cmp_fs_s_done

LEAF(get_cmp_s, 0)
	srl	a3, a0, 11 - 3			# get FS field
	and	a3, a3, 0x1f << 3		# mask FS field
	ld	a3, cmp_fs_s_tbl(a3)		# switch on register number
	j	a3

	.rdata
cmp_fs_s_tbl:
	.text

	CMP_FS_S(f0)
	CMP_FS_S(f1)
	CMP_FS_S(f2)
	CMP_FS_S(f3)
	CMP_FS_S(f4)
	CMP_FS_S(f5)
	CMP_FS_S(f6)
	CMP_FS_S(f7)
	CMP_FS_S(f8)
	CMP_FS_S(f9)
	CMP_FS_S(f10)
	CMP_FS_S(f11)
	CMP_FS_S(f12)
	CMP_FS_S(f13)
	CMP_FS_S(f14)
	CMP_FS_S(f15)
	CMP_FS_S(f16)
	CMP_FS_S(f17)
	CMP_FS_S(f18)
	CMP_FS_S(f19)
	CMP_FS_S(f20)
	CMP_FS_S(f21)
	CMP_FS_S(f22)
	CMP_FS_S(f23)
	CMP_FS_S(f24)
	CMP_FS_S(f25)
	CMP_FS_S(f26)
	CMP_FS_S(f27)
	CMP_FS_S(f28)
	CMP_FS_S(f29)
	CMP_FS_S(f30)
	CMP_FS_S(f31)

cmp_fs_s_done:
	srl	t1, t0, 23			# get exponent
	and	t1, t1, 0xFF
	and	t2, t0, 0x7FFFFF		# get fraction
	srl	t0, t0, 31			# get sign

#define CMP_FT_S(n) \
	.rdata;				\
	.dword	cmp_ft_s_/**/n;		\
	.text;				\
cmp_ft_s_/**/n:				\
	mfc1	ta0, $/**/n;		\
	b	cmp_ft_s_done

	srl	a3, a0, 16 - 3			# get FT field
	and	a3, a3, 0x1f << 3		# mask FT field
	ld	a3, cmp_ft_s_tbl(a3)		# switch on register number
	j	a3

	.rdata
cmp_ft_s_tbl:
	.text

	CMP_FT_S(f0)
	CMP_FT_S(f1)
	CMP_FT_S(f2)
	CMP_FT_S(f3)
	CMP_FT_S(f4)
	CMP_FT_S(f5)
	CMP_FT_S(f6)
	CMP_FT_S(f7)
	CMP_FT_S(f8)
	CMP_FT_S(f9)
	CMP_FT_S(f10)
	CMP_FT_S(f11)
	CMP_FT_S(f12)
	CMP_FT_S(f13)
	CMP_FT_S(f14)
	CMP_FT_S(f15)
	CMP_FT_S(f16)
	CMP_FT_S(f17)
	CMP_FT_S(f18)
	CMP_FT_S(f19)
	CMP_FT_S(f20)
	CMP_FT_S(f21)
	CMP_FT_S(f22)
	CMP_FT_S(f23)
	CMP_FT_S(f24)
	CMP_FT_S(f25)
	CMP_FT_S(f26)
	CMP_FT_S(f27)
	CMP_FT_S(f28)
	CMP_FT_S(f29)
	CMP_FT_S(f30)

cmp_ft_s_done:
	srl	ta1, ta0, 23			# get exponent
	and	ta1, ta1, 0xFF
	and	ta2, ta0, 0x7FFFFF		# get fraction
	srl	ta0, ta0, 31			# get sign
	j	ra
END(get_cmp_s)

/*----------------------------------------------------------------------------
 * get_cmp_d --
 *
 *	Read (double precision) the FS register (bits 15-11) and
 *	the FT register (bits 20-16) and break up into fields.
 *	This is an internal routine used by MipsEmulateFP only.
 *
 * Results:
 *	t0	contains the sign
 *	t1	contains the (biased) exponent
 *	t2	contains the fraction
 *	ta0	contains the sign
 *	ta1	contains the (biased) exponent
 *	ta2	contains the fraction
 *
 *----------------------------------------------------------------------------
 */
#define CMP_FS_D(n) \
	.rdata;				\
	.dword	cmp_fs_d_/**/n;		\
	.text;				\
cmp_fs_d_/**/n:				\
	dmfc1	t2, $/**/n;		\
	b	cmp_fs_d_done

LEAF(get_cmp_d, 0)
	srl	a3, a0, 11 - 3			# get FS field
	and	a3, a3, 0x1f << 3		# mask FS field
	ld	a3, cmp_fs_d_tbl(a3)		# switch on register number
	j	a3

	.rdata
cmp_fs_d_tbl:
	.text

	CMP_FS_D(f0)
	CMP_FS_D(f1)
	CMP_FS_D(f2)
	CMP_FS_D(f3)
	CMP_FS_D(f4)
	CMP_FS_D(f5)
	CMP_FS_D(f6)
	CMP_FS_D(f7)
	CMP_FS_D(f8)
	CMP_FS_D(f9)
	CMP_FS_D(f10)
	CMP_FS_D(f11)
	CMP_FS_D(f12)
	CMP_FS_D(f13)
	CMP_FS_D(f14)
	CMP_FS_D(f15)
	CMP_FS_D(f16)
	CMP_FS_D(f17)
	CMP_FS_D(f18)
	CMP_FS_D(f19)
	CMP_FS_D(f20)
	CMP_FS_D(f21)
	CMP_FS_D(f22)
	CMP_FS_D(f23)
	CMP_FS_D(f24)
	CMP_FS_D(f25)
	CMP_FS_D(f26)
	CMP_FS_D(f27)
	CMP_FS_D(f28)
	CMP_FS_D(f29)
	CMP_FS_D(f30)
	CMP_FS_D(f31)

cmp_fs_d_done:
	dsrl	t0, t2, 63			# get sign
	dsrl	t1, t2, 52			# get exponent
	and	t1, t1, 0x7FF
	dsll	t2, 12
	dsrl	t2, 12				# get fraction

#define CMP_FT_D(n) \
	.rdata;				\
	.dword	cmp_ft_d_/**/n;		\
	.text;				\
cmp_ft_d_/**/n:				\
	dmfc1	ta2, $/**/n;		\
	b	cmp_ft_d_done

	srl	a3, a0, 16 - 3			# get FT field
	and	a3, a3, 0x1f << 3		# mask FT field
	ld	a3, cmp_ft_d_tbl(a3)		# switch on register number
	j	a3

	.rdata
cmp_ft_d_tbl:
	.text

	CMP_FT_D(f0)
	CMP_FT_D(f1)
	CMP_FT_D(f2)
	CMP_FT_D(f3)
	CMP_FT_D(f4)
	CMP_FT_D(f5)
	CMP_FT_D(f6)
	CMP_FT_D(f7)
	CMP_FT_D(f8)
	CMP_FT_D(f9)
	CMP_FT_D(f10)
	CMP_FT_D(f11)
	CMP_FT_D(f12)
	CMP_FT_D(f13)
	CMP_FT_D(f14)
	CMP_FT_D(f15)
	CMP_FT_D(f16)
	CMP_FT_D(f17)
	CMP_FT_D(f18)
	CMP_FT_D(f19)
	CMP_FT_D(f20)
	CMP_FT_D(f21)
	CMP_FT_D(f22)
	CMP_FT_D(f23)
	CMP_FT_D(f24)
	CMP_FT_D(f25)
	CMP_FT_D(f26)
	CMP_FT_D(f27)
	CMP_FT_D(f28)
	CMP_FT_D(f29)
	CMP_FT_D(f30)
	CMP_FT_D(f31)

cmp_ft_d_done:
	dsrl	ta0, ta2, 63			# get sign
	dsrl	ta1, ta2, 52			# get exponent
	and	ta1, ta1, 0x7FF
	dsll	ta2, 12
	dsrl	ta2, 12				# get fraction
	j	ra
END(get_cmp_d)

/*----------------------------------------------------------------------------
 * set_fd_s --
 *
 *	Write (single precision) the FD register (bits 10-6).
 *	This is an internal routine used by MipsEmulateFP only.
 *
 * Arguments:
 *	a0	contains the FP instruction
 *	t0	contains the sign
 *	t1	contains the (biased) exponent
 *	t2	contains the fraction
 *
 * set_fd_word --
 *
 *	Write (integer) the FD register (bits 10-6).
 *	This is an internal routine used by MipsEmulateFP only.
 *
 * Arguments:
 *	a0	contains the FP instruction
 *	t2	contains the integer
 *
 *----------------------------------------------------------------------------
 */
#define SET_FD_S(n) \
	.rdata;				\
	.dword	set_fd_s_/**/n;		\
	.text;				\
set_fd_s_/**/n:				\
	mtc1	t2, $/**/n;		\
	j	ra

LEAF(set_fd_s, 0)
	sll	t0, t0, 31			# position sign
	sll	t1, t1, 23			# position exponent
	or	t2, t2, t0
	or	t2, t2, t1
ALEAF(set_fd_word)
	srl	a3, a0, 6 - 3			# get FD field
	and	a3, a3, 0x1f << 3		# mask FT field
	ld	a3, set_fd_s_tbl(a3)		# switch on register number
	j	a3

	.rdata
set_fd_s_tbl:
	.text

	SET_FD_S(f0)
	SET_FD_S(f1)
	SET_FD_S(f2)
	SET_FD_S(f3)
	SET_FD_S(f4)
	SET_FD_S(f5)
	SET_FD_S(f6)
	SET_FD_S(f7)
	SET_FD_S(f8)
	SET_FD_S(f9)
	SET_FD_S(f10)
	SET_FD_S(f11)
	SET_FD_S(f12)
	SET_FD_S(f13)
	SET_FD_S(f14)
	SET_FD_S(f15)
	SET_FD_S(f16)
	SET_FD_S(f17)
	SET_FD_S(f18)
	SET_FD_S(f19)
	SET_FD_S(f20)
	SET_FD_S(f21)
	SET_FD_S(f22)
	SET_FD_S(f23)
	SET_FD_S(f24)
	SET_FD_S(f25)
	SET_FD_S(f26)
	SET_FD_S(f27)
	SET_FD_S(f28)
	SET_FD_S(f29)
	SET_FD_S(f30)
	SET_FD_S(f31)

END(set_fd_s)

/*----------------------------------------------------------------------------
 * set_fd_d --
 *
 *	Write (double precision) the FT register (bits 10-6).
 *	This is an internal routine used by MipsEmulateFP only.
 *
 * Arguments:
 *	a0	contains the FP instruction
 *	t0	contains the sign
 *	t1	contains the (biased) exponent
 *	t2	contains the fraction
 *
 *----------------------------------------------------------------------------
 */
#define SET_FD_D(n) \
	.rdata;				\
	.dword	set_fd_d_/**/n;		\
	.text;				\
set_fd_d_/**/n:				\
	dmtc1	t0, $/**/n;		\
	j	ra

LEAF(set_fd_d, 0)
	dsll	t0, 63				# set sign
	dsll	t1, t1, 52			# set exponent
	or	t0, t0, t1
	or	t0, t0, t2			# set fraction
	srl	a3, a0, 6 - 3			# get FD field
	and	a3, a3, 0x1f << 3		# mask FD field
	ld	a3, set_fd_d_tbl(a3)		# switch on register number
	j	a3

	.rdata
set_fd_d_tbl:
	.text

	SET_FD_D(f0)
	SET_FD_D(f1)
	SET_FD_D(f2)
	SET_FD_D(f3)
	SET_FD_D(f4)
	SET_FD_D(f5)
	SET_FD_D(f6)
	SET_FD_D(f7)
	SET_FD_D(f8)
	SET_FD_D(f9)
	SET_FD_D(f10)
	SET_FD_D(f11)
	SET_FD_D(f12)
	SET_FD_D(f13)
	SET_FD_D(f14)
	SET_FD_D(f15)
	SET_FD_D(f16)
	SET_FD_D(f17)
	SET_FD_D(f18)
	SET_FD_D(f19)
	SET_FD_D(f20)
	SET_FD_D(f21)
	SET_FD_D(f22)
	SET_FD_D(f23)
	SET_FD_D(f24)
	SET_FD_D(f25)
	SET_FD_D(f26)
	SET_FD_D(f27)
	SET_FD_D(f28)
	SET_FD_D(f29)
	SET_FD_D(f30)
	SET_FD_D(f31)

END(set_fd_d)

/*----------------------------------------------------------------------------
 * renorm_fs_s --
 *
 * Results:
 *	t1	unbiased exponent
 *	t2	normalized fraction
 *
 *----------------------------------------------------------------------------
 */
LEAF(renorm_fs_s, 0)
/*
 * Find out how many leading zero bits are in t2 and put in t9.
 */
	move	v0, t2
	move	t9, zero
	srl	v1, v0, 16
	bne	v1, zero, 1f
	addu	t9, 16
	sll	v0, 16
1:
	srl	v1, v0, 24
	bne	v1, zero, 1f
	addu	t9, 8
	sll	v0, 8
1:
	srl	v1, v0, 28
	bne	v1, zero, 1f
	addu	t9, 4
	sll	v0, 4
1:
	srl	v1, v0, 30
	bne	v1, zero, 1f
	addu	t9, 2
	sll	v0, 2
1:
	srl	v1, v0, 31
	bne	v1, zero, 1f
	addu	t9, 1
/*
 * Now shift t2 the correct number of bits.
 */
1:
	subu	t9, t9, SLEAD_ZEROS	# dont count normal leading zeros
	li	t1, SEXP_MIN
	subu	t1, t1, t9		# adjust exponent
	sll	t2, t2, t9
	j	ra
END(renorm_fs_s)

/*----------------------------------------------------------------------------
 * renorm_fs_d --
 *
 * Results:
 *	t1	unbiased exponent
 *	t2	normalized fraction
 *
 *----------------------------------------------------------------------------
 */
LEAF(renorm_fs_d, 0)
/*
 * Find out how many leading zero bits are in t2 and put in t9.
 */
	move	v0, t2
	move	t9, zero
	dsrl	v1, v0, 32
	bne	v1, zero, 1f
	addu	t9, 32
	dsll	v0, 32
1:
	dsrl	v1, v0, 16
	bne	v1, zero, 1f
	addu	t9, 16
	dsll	v0, 16
1:
	dsrl	v1, v0, 24
	bne	v1, zero, 1f
	addu	t9, 8
	dsll	v0, 8
1:
	dsrl	v1, v0, 28
	bne	v1, zero, 1f
	addu	t9, 4
	dsll	v0, 4
1:
	dsrl	v1, v0, 30
	bne	v1, zero, 1f
	addu	t9, 2
	dsll	v0, 2
1:
	dsrl	v1, v0, 31
	bne	v1, zero, 1f
	addu	t9, 1
/*
 * Now shift t2 the correct number of bits.
 */
1:
	subu	t9, t9, DLEAD_ZEROS	# dont count normal leading zeros
	li	t1, DEXP_MIN
	subu	t1, t9			# adjust exponent
	dsll	t2, t9
	j	ra
END(renorm_fs_d)

/*----------------------------------------------------------------------------
 * renorm_ft_s --
 *
 * Results:
 *	ta1	unbiased exponent
 *	ta2	normalized fraction
 *
 *----------------------------------------------------------------------------
 */
LEAF(renorm_ft_s, 0)
/*
 * Find out how many leading zero bits are in ta2 and put in t9.
 */
	move	v0, ta2
	move	t9, zero
	srl	v1, v0, 16
	bne	v1, zero, 1f
	addu	t9, 16
	sll	v0, 16
1:
	srl	v1, v0, 24
	bne	v1, zero, 1f
	addu	t9, 8
	sll	v0, 8
1:
	srl	v1, v0, 28
	bne	v1, zero, 1f
	addu	t9, 4
	sll	v0, 4
1:
	srl	v1, v0, 30
	bne	v1, zero, 1f
	addu	t9, 2
	sll	v0, 2
1:
	srl	v1, v0, 31
	bne	v1, zero, 1f
	addu	t9, 1
/*
 * Now shift ta2 the correct number of bits.
 */
1:
	subu	t9, t9, SLEAD_ZEROS	# dont count normal leading zeros
	li	ta1, SEXP_MIN
	subu	ta1, t9			# adjust exponent
	sll	ta2, t9
	j	ra
END(renorm_ft_s)

/*----------------------------------------------------------------------------
 * renorm_ft_d --
 *
 * Results:
 *	ta1	unbiased exponent
 *	ta2	normalized fraction
 *
 *----------------------------------------------------------------------------
 */
LEAF(renorm_ft_d, 0)
/*
 * Find out how many leading zero bits are in ta2 and put in t9.
 */
	move	v0, ta2
	move	t9, zero
	dsrl	v1, v0, 32
	bne	v1, zero, 1f
	addu	t9, 32
	dsll	v0, 32
1:
	dsrl	v1, v0, 16
	bne	v1, zero, 1f
	addu	t9, 16
	dsll	v0, 16
1:
	dsrl	v1, v0, 24
	bne	v1, zero, 1f
	addu	t9, 8
	dsll	v0, 8
1:
	dsrl	v1, v0, 28
	bne	v1, zero, 1f
	addu	t9, 4
	dsll	v0, 4
1:
	dsrl	v1, v0, 30
	bne	v1, zero, 1f
	addu	t9, 2
	dsll	v0, 2
1:
	dsrl	v1, v0, 31
	bne	v1, zero, 1f
	addu	t9, 1
/*
 * Now shift ta2 the correct number of bits.
 */
1:
	subu	t9, t9, DLEAD_ZEROS	# dont count normal leading zeros
	li	ta1, DEXP_MIN
	subu	ta1, t9			# adjust exponent
	dsll	ta2, t9
	j	ra
END(renorm_ft_d)
